package com.steakliu.apigenerator;

import com.alibaba.fastjson.JSONArray;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.*;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Locale;

/**
 * @author 刘牌
 * @Title:
 * @date 2022-06-2022:47
 */
@Component
public class ApiDoc implements BeanPostProcessor {
    @SneakyThrows
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.contains("Controller")) {
            RestController restController = bean.getClass().getAnnotation(RestController.class);
            RequestMapping requestMapping = bean.getClass().getAnnotation(RequestMapping.class);
            //TODO 接口说明，如果有swagger的接口说明，那么就使用，如果没有，那么就不使用
            Api api = bean.getClass().getAnnotation(Api.class);

            //TODO url,方法名
            Method[] methods = bean.getClass().getMethods();
            for (Method method : methods) {
               DocEntity docEntity = new DocEntity();
                /**
                 * TODO 设置所属Controller
                 */
                docEntity.setController(beanName.substring(0,1).toUpperCase(Locale.ROOT) + beanName.substring(1,beanName.length()));
                ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
                String methodOps = "";
                if (null != apiOperation){
                    methodOps = apiOperation.value();
                }
                if (null != api) {
                    docEntity.setApiDesc(api.tags()[0]
                            .replace("module","")
                            .replace("【","")
                            .replace("】","")+"【"+methodOps+"】");
                } else {
                    docEntity.setApiDesc(beanName);
                }

                //去除Object带的方法
                String name = method.getName();
                if (name.equals("wait") || name.equals("equals") || name.equals("toString") || name.equals("hashCode") || name.equals("getClass") || name.equals("notify") || name.equals("notifyAll")) {
                    continue;
                } else {
                    /**
                     * TODO 设置方法名
                     */
                    docEntity.setMethodName(name);

                    //类上面的RequestMapping  url
                    String classMappingUrl = "";
                    if (null != requestMapping) {
                        if (null != requestMapping.value()[0]) {
                            classMappingUrl = requestMapping.value()[0];
                        }
                    }
                    //方法上的映射url
                    GetMapping getMapping = method.getAnnotation(GetMapping.class);
                    RequestMapping methodRequestMapping = method.getAnnotation(RequestMapping.class);
                    PostMapping postMapping = method.getAnnotation(PostMapping.class);
                    DeleteMapping deleteMapping = method.getAnnotation(DeleteMapping.class);
                    PatchMapping patchMapping = method.getAnnotation(PatchMapping.class);
                    PutMapping putMapping = method.getAnnotation(PutMapping.class);

                    /**
                     * TODO 设置url
                     */
                    if (null != getMapping) {
                        if (getMapping.value().length > 0) {
                            docEntity.setUrl(classMappingUrl + getMapping.value()[0]);
                        } else {
                            docEntity.setUrl(classMappingUrl + name);
                        }
                    }
                    if (null != methodRequestMapping) {
                        if (methodRequestMapping.value().length > 0) {
                            docEntity.setUrl(classMappingUrl + methodRequestMapping.value()[0]);
                        } else {
                            docEntity.setUrl(classMappingUrl + name);
                        }
                    }
                    if (null != postMapping) {
                        //如果映射路径没有填写，那么使用方法名作为路径
                        if (postMapping.value().length > 0) {
                            docEntity.setUrl(classMappingUrl + postMapping.value()[0]);
                        } else {
                            docEntity.setUrl(classMappingUrl + name);
                        }
                    }
                    if (null != deleteMapping) {
                        docEntity.setUrl(classMappingUrl + deleteMapping.value()[0]);
                    }
                    if (null != patchMapping) {
                        docEntity.setUrl(classMappingUrl + patchMapping.value()[0]);
                    }
                    if (null != putMapping) {
                        if (putMapping.value().length > 0) {
                            docEntity.setUrl(classMappingUrl + putMapping.value()[0]);
                        } else {
                            docEntity.setUrl(classMappingUrl + name);
                        }
                    }

                    /**
                     * TODO 入参
                     */
                    Class<?>[] parameters = method.getParameterTypes();
                    Parameter[] methodParameters = method.getParameters();
                    //参数注解 PathVariable , RequestBody等
                    Annotation[][] parameterAnnotations = method.getParameterAnnotations();
                    //如果使用的是注解参数
                    if (parameterAnnotations.length > 0) {
                        for (Annotation[] parameterAnnotation : parameterAnnotations) {
                            for (Annotation annotation : parameterAnnotation) {
                                if (annotation instanceof PathVariable) {
                                    PathVariable pathVariable = (PathVariable) annotation;
                                    ArrayList<String> arrayList = new ArrayList<>();
                                    for (Parameter parameter : methodParameters) {
                                        arrayList.add("{" + parameter.getName() + "}");
                                    }
                                    docEntity.setInParamDesc(StringUtils.join(arrayList));
                                }
                                if (annotation instanceof RequestBody) {

                                }
                                if (annotation instanceof RequestParam) {
                                    RequestParam requestParam = (RequestParam) annotation;
                                    ArrayList<String> arrayList = new ArrayList<>();
                                    if ("".equals(requestParam.value())) {
                                        arrayList.add(requestParam.value() + "=");
                                    } else {
                                        for (Parameter parameter : methodParameters) {
                                            arrayList.add(parameter.getName() + "=");
                                        }
                                    }
                                }
                                //其他注解
                                else {

                                }
                            }
                        }
                    }
                    //不是使用注解参数，那么就是GET方式
                    else {
                        Class<?>[] parameterTypes = method.getParameterTypes();
                        ArrayList<Object> paramsList = new ArrayList<>();
                        for (Class<?> parameterType : parameterTypes) {
                            Field[] fields = parameterType.getDeclaredFields();
                            for (Field field : fields) {
                                paramsList.add(field.getName());
                            }
                        }
                        docEntity.setInParamDesc(StringUtils.join(paramsList, "&"));
                    }

                    /**
                     * TODO 出参
                     */
                    /**
                     * 返回类型
                     */
                    Class<?> returnType = method.getReturnType();
                    String typeName = method.getGenericReturnType().getTypeName();
                    String data = null;
                    //如果类型为统一返回类型，那么解析出泛型参数
//                    if (returnType == AjaxResult.class) {
//                        AjaxResult<Object> ajaxResult = new AjaxResult<>();
//                        //如果设置了泛型参数
//                        if (typeName.contains("<") && typeName.contains(">")) {
//                            int start = typeName.indexOf("<") + 1;
//                            int end = typeName.indexOf(">");
//                            String result = typeName.substring(start, end);
//                            Class<?> forName = Class.forName(result);
//                            //data = returnType.getMethod("setData", Object.class).invoke(ajaxResult, forName.newInstance());
//                        } else {
//                            data = ajaxResult.toString();
//                        }
//                    }
                    //返回值为void
                     if (returnType == void.class) {
                        data = "void";
                    }
                    //其他返回类型，直接返回实例
                    else {
                        try {
                            data = null;
                        }catch (Exception e){
                            e.printStackTrace();
                        }
                    }
                    docEntity.setOutParamDesc(data);
                }
                CacheApi.docEntities.add(docEntity);
            }
        }
        System.out.println("docList  " + JSONArray.toJSONString(CacheApi.docEntities));
        return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }
}
